#include "socket.h"

StratumSocket::StratumSocket(int sock):m_buff_len(0), m_sock(sock){
    struct timeval timeout{};
    timeout.tv_sec = g_socket_recv_timeout;
    timeout.tv_usec = 0;
    setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

    if (!g_handle_haproxy_ips) {
        int res = 0;
        struct sockaddr_in name{};
        socklen_t len = sizeof(name);
        memset(&name, 0, len);
        res = getpeername(m_sock, (struct sockaddr*)&name, &len);
        // 网络(二进制)格式转为点分十进制格式,network to presentation format
        inet_ntop(AF_INET, &name.sin_addr, m_ip, 64);
        res = getpeername(m_sock, (struct sockaddr*)&name, &len);
        m_port = ntohs(name.sin_port);
    } else {
        realIp();
    }
}

StratumSocket::StratumSocket(StratumSocket& that) {

}

StratumSocket::~StratumSocket() {
    if (g_debuglog_socket) {
        debuglog("socket close\n");
    }
    if (m_sock) {
        close(m_sock);
    }
    m_sock = 0;
}

bool StratumSocket::connected() {
    return m_sock > 0;
}

void StratumSocket::realIp() {
    int size, ret;
    const char* v2sig = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
    do {
        ret = recv(m_sock, &hdr, sizeof(hdr), MSG_PEEK);
    } while (ret == -1 && errno == EINTR);

    if (ret >= (16 + ntohs(hdr.v2.len)) && memcmp(&hdr.v2, v2sig, 12) == 0 && (hdr.v2.ver_cmd & 0xF0) == 0x20 &&
        hdr.v2.fam == 0x11) {
        inet_ntop(AF_INET, &hdr.v2.addr.ip4.src_addr, m_ip, 64);
        m_port = ntohs(hdr.v2.addr.ip4.src_port);
        size = 16 + ntohs(hdr.v2.len);
        do {
            ret = recv(m_sock, &hdr, size, 0);
        } while (ret == -1 && errno == EINTR);
    } else {
        struct sockaddr_in name{};
        socklen_t len = sizeof(name);
        memset(&name, 0, len);
        int res = getpeername(m_sock, (struct sockaddr*)&name, &len);
        inet_ntop(AF_INET, &name.sin_addr, m_ip,64);
        res = getsockname(m_sock, (struct sockaddr*)&name, &len);
        m_port = ntohs(name.sin_port);
    }
}
